/*
 * @Descripttion: 配置解析器
 * @version:
 * @Author: lfzxs@qq.com
 * @Date: 2023-06-19 10:22:18
 * @LastEditors: lfzxs@qq.com
 * @LastEditTime: 2023-06-21 14:11:42
 */
package config

import (
	"reflect"
	"strings"

	"gitee.com/g_boot/configkit/loader"
	"gitee.com/g_boot/configkit/resolver"
	"gitee.com/g_boot/configkit/system"
	"golang.org/x/exp/slog"
	"github.com/pkg/errors"
)

type YamlConfig struct {
	Data     map[string]any
	Loader   loader.LoaderService
	Resolver resolver.ResolverService
	URI      string
}

var (
	// Prefix array for trying searching in local system.
	localSystemTryFolders = []string{"", "config/", "manifest/config/"}
	defaultFileName = "config.yaml"
)


func DefaultConfig() *YamlConfig{

	rootPath := system.RootPath()

	filepath := rootPath + "/" + defaultFileName

	yaml_config,err := FromFile(filepath)

	if(err != nil){
		return nil 
	}

	return &yaml_config
}

func FromFile(filePath string)(cfg YamlConfig,err error){

	fileUri := "file://"+ filePath
	loadService := loader.YmlLoader{}

	resolverService := resolver.StringInterpolation{}
	
	yaml_config := YamlConfig{}
	yaml_config.Loader = &loadService
	yaml_config.Resolver = &resolverService
	yaml_config.URI = fileUri

	yaml_config.Build(nil)

	return yaml_config,nil
}

func FromFolders(fileName string, searchFolds ...string)(cfg YamlConfig,err error){
	if len(searchFolds) == 0 {
		searchFolds = localSystemTryFolders
	}

	rootPath := system.RootPath()
	for _, value := range searchFolds {
		absolutePath := rootPath + "/" + value + fileName
		if system.FileExists(absolutePath) {
			return FromFile(absolutePath)
		}
	}
	err = errors.Errorf("no search paths:%s,%v", rootPath, searchFolds)
	return 
}


// 构建配置对象
func (sf *YamlConfig) Build(env ...map[string]any) {
	cfgs, err := sf.Loader.LoadFromURI(sf.URI)

	if err != nil {
		slog.Error("文件加载出错:", err)
	}

	sf.Data, err = sf.Resolver.Resolution(cfgs)
	if err != nil {
		slog.Error("文件解析出错:", err)
	}
}


// 获取配置值
func (sf *YamlConfig) GetValue(name string) any {
	path := strings.Split(name, ".")
	data := sf.Data
	for key, value := range path {
		v, ok := data[value]
		if !ok {
			break
		}
		if (key + 1) == len(path) {
			return v
		}
		if reflect.TypeOf(v).String() == "map[string]interface {}" {
			data, ok = v.(map[string]any)
			if !ok {
				break
			}

		}
	}
	return nil
}
